package akka.http.scaladsl.marshallers.json4s

import akka.http.scaladsl.marshalling._
import akka.http.scaladsl.model.MediaTypes.`application/json`
import akka.http.scaladsl.model.{ContentTypes, HttpCharsets}
import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshaller}
import akka.stream.Materializer
import org.json4s._

import scala.language.implicitConversions

/**
  * A trait providing automatic to and from JSON marshalling/unmarshalling using an in-scope *spray-json* protocol.
  */
trait BaseJson4sSupport {

  protected def serialization: Serialization

  implicit def json4sFormats: Formats

  implicit def json4sMarshaller[T <: AnyRef] =
    Marshaller.StringMarshaller.wrap(ContentTypes.`application/json`)(serialization.write)


  implicit def json4sUnmarshaller[T: Manifest](implicit mat: Materializer): FromEntityUnmarshaller[T] =
    Unmarshaller.byteStringUnmarshaller.forContentTypes(`application/json`).mapWithCharset { (data, charset) ⇒
      val inputString = if (charset == HttpCharsets.`UTF-8`) data.decodeString("UTF-8") else data.decodeString(charset.nioCharset.name)
      serialization.read[T](inputString)
    }
}

trait Json4sSupport extends BaseJson4sSupport {

  override protected def serialization: Serialization = org.json4s.native.Serialization
}


trait JackJsonJson4sSupport extends BaseJson4sSupport {

  override protected def serialization: Serialization = org.json4s.jackson.Serialization
}

